package com.lcf.feign.aspect;

import com.lcf.base.exception.SysException;
import com.lcf.common.utils.ServletUtils;
import com.lcf.feign.annotation.FeignIgnore;
import jakarta.servlet.http.HttpServletRequest;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Objects;

import static com.lcf.base.constant.SysConstant.FEIGN_HEADER;
import static com.lcf.base.constant.SysConstant.FEIGN_HEADER_VALUE;

/**
 * 描述：feign aop
 *
 * @author lcf
 * @since 2025/3/5 13:58
 */
@Order(1)
@Aspect
@Component
public class FeignRequestAspect {
    @Pointcut("within(@org.springframework.web.bind.annotation.RestController *)")
    public void controllerPointcut() {
    }

    @Before("controllerPointcut()")
    public void checkFeignRequest(JoinPoint joinPoint) {
        // 禁止前端直接调用feign对应的controller
        // 检查是否有接口带有 @FeignClient 注解
        // 如果有，则检查请求头中是否有 FEIGN_HEADER_VALUE，由自定义的FeignInterceptor进行设置
        // 如果没有，则抛出异常
        Class<?> controllerClass = joinPoint.getTarget().getClass();
        boolean isFeignClient = Arrays.stream(controllerClass.getInterfaces())
                .anyMatch(interfaceClass -> interfaceClass.isAnnotationPresent(FeignClient.class));

        if (isFeignClient) {
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            Method method = signature.getMethod();

            // 检查类或方法是否带有 @FeignIgnore 注解
            // 如果带有 @FeignIgnore 注解，则跳过检查
            if (controllerClass.isAnnotationPresent(FeignIgnore.class) || method.isAnnotationPresent(FeignIgnore.class)) {
                return;
            }

            HttpServletRequest request = ServletUtils.getRequest();
            if (request != null && !Objects.equals(FEIGN_HEADER_VALUE, request.getHeader(FEIGN_HEADER))) {
                throw new SysException("内部接口，禁止调用");
            }
        }
    }
}
